﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureBasicWall.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "GmIStructureFactory.h"
#include "IDocument.h"
#include "IElementModelShape.h"
#include "IElementParameters.h"
#include "IElementPosition.h"
#include "IElementStatus.h"
#include "IExternalDataComponent.h"
#include "IFamily.h"
#include "IInstance.h"
#include "IInstanceType.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IPositionCurve2d.h"
#include "IPositionTwoAssociatedPlanes.h"
#include "IRegenerator.h"
#include "LevelUtils.h"
#include "StructureBasicWallHeightParameterUpdater.h"
#include "StructureGeneralParameterValidator.h"
#include "StructureInstanceLevelUtils.h"
#include "StructureInstanceUtils.h"
#include "StructureWallInput.h"
#include "StructureWallParametersCustomizer.h"
#include "StructureWallPositionPoints.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

DEFINE_STRUCTURE_INSTANCE_BASE_DATA_METHODS(StructureBasicWall, BaseData);

DBOBJECT_DATA_DEFINE(StructureBasicWall)
{
}


bool StructureBasicWall::CustomizeParameters()
{
    IElement * pOwnerElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwnerElement, L"GetOwnerElement()返回空指针？",L"GDMPLab",L"2024-03-30");
    IElementParameters * pElementParameters = pOwnerElement->GetElementParameters();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementParameters, L"pOwnerElement->GetElementParameters()返回空指针？",L"GDMPLab",L"2024-03-30");

    bool res = pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(ParameterValidatorCustomizedOverride, PARAMETER_UID(TopOffsetBuiltInParameter)));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(res, L"设置顶部偏移参数定制器失败？",L"GDMPLab",L"2024-03-30");
    res = pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(ParameterValidatorCustomizedOverride, PARAMETER_UID(BottomOffsetBuiltInParameter)));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(res, L"设置底部偏移参数定制器失败？",L"GDMPLab",L"2024-03-30");
    res = pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(ParameterValidatorCustomizedOverride, PARAMETER_UID(TopAssociatedLevelBuiltInParameter)));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(res, L"设置顶部标高参数定制器失败？",L"GDMPLab",L"2024-03-30");
    res = pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(ParameterValidatorCustomizedOverride, PARAMETER_UID(ElementAssociatedLevelBuiltInParameter)));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(res, L"设置底部标高参数定制器失败？",L"GDMPLab",L"2024-03-30");
    res = pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(GeneralHeightBuiltInParameterOverride, pOwnerElement, PARAMETER_UID(WallHeightBuiltInParameter)));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(res, L"设置高度参数定制器失败？",L"GDMPLab",L"2024-03-30");
    return true;
}

StructureBasicWall *gcmp::StructureBasicWall::Create(const StructureWallInput *pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IInstance* pInstance = nullptr;
    if (pInput->PositionType == ElementInputPositionType::Line)
    {
        pInstance = StructureBasicWall::CreateStraightWall(pInput);
    }
    else if (pInput->PositionType == ElementInputPositionType::ArcBy3Points)
    {
        pInstance = StructureBasicWall::CreateArcBy3PtsWall(pInput);
    }
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    StructureBasicWall* pBasicWall = StructureBasicWall::Get(pInstance);
    pBasicWall->CustomizeParameters();
    return pBasicWall;
}

const StructureBasicWall *gcmp::StructureBasicWall::Get(const IInstance *pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    if (const IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        const IExternalData* pData = pExternalDataComponent->FindExternalData(StructureBasicWall::GetStaticClassSchema()->GetName());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pData, L"pData为空",L"GDMPLab",L"2024-03-30");

        return quick_cast<StructureBasicWall>(pData);
    }
    return nullptr;
}

StructureBasicWall *gcmp::StructureBasicWall::Get(IInstance *pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    if (IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        IExternalData* pData = pExternalDataComponent->FindExternalData(StructureBasicWall::GetStaticClassSchema()->GetName());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pData, L"pData为空",L"GDMPLab",L"2024-03-30");

        return quick_cast<StructureBasicWall>(pData);
    }
    return nullptr;
}

void StructureBasicWall::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
    GetBaseDataFW__()->UpdateForWeakParentDeletion(deletedElementIds);
}
void StructureBasicWall::ReportParents(IElementParentReporter& reporter) const
{
    GetBaseData__()->ReportParents(reporter);
}

void StructureBasicWall::GetCalculators(ICalculatorCollection * calculators) const
{
    GetBaseData__()->GetCalculators(calculators);
}

void StructureBasicWall::ReportParameterDefinitions(std::vector<int>* pParamDefIds) const
{
    GetBaseData__()->ReportParameterDefinitions(pParamDefIds);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDefIds, L"pParamDefIds为空",L"GDMPLab",L"2024-03-30");

}

OwnerPtr<IParameter> StructureBasicWall::GetNativeParameter(int paramDefId) const
{
    OwnerPtr<IParameter> param = GetBaseData__()->GetNativeParameter(paramDefId);
    if (IParameter::IsValidParameter(param))
        return param;

    return nullptr;
}

bool StructureBasicWall::SetNativeParameter(const IParameter *param, std::wstring* errorMsg/* = nullptr*/)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMPLab",L"2024-03-30");

    if (GetBaseDataFW__()->SetNativeParameter(param, errorMsg))
        return true;

    return false;
}

bool StructureBasicWall::IsParameterModifiable(int paramDefId) const
{
    if (!GetBaseData__()->IsParameterModifiable(paramDefId))
        return false;
    return true;
}

void StructureBasicWall::Report(const ICopyContext & copyContext, ICopyStrategyReporter& reporter) const
{
    GetBaseData__()->Report(copyContext, reporter);
}

IInstance* StructureBasicWall::CreateStraightWall(const StructureWallInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInput->Document;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstanceType* pInstanceType = quick_cast<IInstanceType>(pDoc->GetElement(pInput->InstanceTypeId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstanceType, L"pInstanceType为空",L"GDMPLab",L"2024-03-30");

    std::wstring instanceTypeName = pInstanceType->GetBasicInformation()->GetName();

    IInstance* pInstance = IInstance::Create(pDoc, pInput->FamilyId, instanceTypeName, L"墙实例", pInput->CanBeShared, pInput->CreationOption, pInput->IsCreateGeometryRelationshipComponent);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    //设置instance的Unidentity
    if (pInput->categoryUid.IsValid())
    {
        pInstance->GetBasicInformation()->SetCategoryUid(pInput->categoryUid);
    }

    //设置实例外部自定义数据
    StructureBasicWall* pWall = StructureBasicWall::RegisterExternalData(pInstance, pInput);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWall, L"pBeam为空",L"GDMPLab",L"2024-03-30");

    //设置墙实例定位参数
    bool bOk = IElementPosition::CreateCurve2dOnTwoAssociatedPlanesPositionBehavior(pInstance
        , pInput->AssociatedPlaneId, pInput->AssociatedPlaneOffset, pInput->PositionPoints, pInput->TopAssociatedPlaneId, pInput->TopPlaneOffset);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"创建定位失败",L"GDMPLab",L"2024-03-30");

    IElementPosition* posBehavior = pInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"无效posBehavior",L"GDMPLab",L"2024-03-30");

    IPositionTwoAssociatedPlanes *pPositionTwoAssociatedPlanes = quick_cast<IPositionTwoAssociatedPlanes>(posBehavior->GetPositionAssociatedPlane());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPositionTwoAssociatedPlanes, L"pPositionTwoAssociatedPlanes为空",L"GDMPLab",L"2024-03-30");

    pPositionTwoAssociatedPlanes->SetBottomOffset(pInput->AssociatedPlaneOffset);
    if (pInput->TopAssociatedPlaneId.IsValid())
    {
        pPositionTwoAssociatedPlanes->SetTopOffset(pInput->TopPlaneOffset);
    }
    else
    {
        //设置墙高预设参数
        OwnerPtr<IParameter> paramWallHeight = pInstance->GetElementParameters()->
            GetParameterByUid(PARAMETER_UID(WallHeightBuiltInParameter));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(paramWallHeight, L"paramWallHeight无效",L"GDMPLab",L"2024-03-30");
        paramWallHeight->SetValueAsDouble(pInput->WallHeight);
        pInstance->GetElementParameters()->SetParameter(paramWallHeight.get());
    }

    //设置墙高内置参数更新行为
    OwnerPtr<IInstanceFamilyParametersUpdater> opParametersUpdater = NEW_AS_OWNER_PTR(StructureBasicWallHeightParameterUpdater, PARAMETER_UID(WallHeightBuiltInParameter));
    posBehavior->SetParametersUpdater(TransferOwnership(opParametersUpdater));

    //设置控制点行为
    pInstance->SetPositionPoints(NEW_AS_OWNER_PTR(StructureWallPositionPoints, pInstance, PARAMETER_UID(LineFamilyPositionCurveSideBuiltInParameter), PARAMETER_UID(CoreThicknessBuiltInParameter)));

    //设置实例所属楼层信息
    ElementId associatedPlaneId = pInput->AssociatedPlaneId;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(associatedPlaneId.IsValid(), L"associatedPlaneId无效",L"GDMPLab",L"2024-03-30");

    const ILevel* pStoreyLevel = nullptr;
    if (pInput->StoreyId.IsValid())
    {
        pStoreyLevel = LevelUtils::GetLevelById(pDoc, pInput->StoreyId);
    }
    else
    {
        pStoreyLevel = StructureInstanceLevelUtils::GetWallStoreyLevelFromPositioningLevel(pDoc, associatedPlaneId);
    }
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStoreyLevel, L"pStoreyLevel为空",L"GDMPLab",L"2024-03-30");
    bOk = StructureInstanceLevelUtils::CreateInstanceStoreyLevel(pInstance, pStoreyLevel);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"SetBeamStoreyLevel失败",L"GDMPLab",L"2024-03-30");

    if (pInstance->GetElementParameters())
    {
        OwnerPtr<IElementParametersCustomizer> opNewCustomizer = 
            NEW_AS_OWNER_PTR(StructureWallParametersCustomizer, pInstance);
        GmStructureDefaultElementParametersCustomizer::SetElementParametersCustomizer(
            pInstance, TransferOwnership(opNewCustomizer));

    }

    const IPositionCurve2d* pPosCurve2d = dynamic_cast<const IPositionCurve2d*>(posBehavior->GetPositionGeometry());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPosCurve2d, L"pPosCurve2d为空",L"GDMPLab",L"2024-03-30");
    bOk = pInstance->SetCoordinateSystemsByCurve(pPosCurve2d->GetBaseCurve());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"SetCoordinateSystemsByCurve失败",L"GDMPLab",L"2024-03-30");

    IElementStatus* pStatus = pInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(pInput->Visible);

    bOk = pDoc->GetRegenerator()->RegenerateElement(pInstance->GetElementId());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"RegenerateElement失败",L"GDMPLab",L"2024-03-30");
    
    return pInstance;
}

IInstance* StructureBasicWall::CreateArcBy3PtsWall(const StructureWallInput* pInput)
{
    //弧形墙与直线墙参数设置暂时一致，故共用一套代码，以后若有需求便更改
    return CreateStraightWall(pInput);
}

StructureBasicWall* StructureBasicWall::RegisterExternalData(IInstance* pInstance, const StructureWallInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<StructureBasicWall> opBasicWall = NEW_AS_OWNER_PTR(StructureBasicWall);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opBasicWall, L"opBasicBeam为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<StructureWall> opBaseData = StructureWall::Create(pInstance, pInput);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opBaseData, L"opBaseData为空",L"GDMPLab",L"2024-03-30");
    opBasicWall->SetBaseData__(TransferOwnership(opBaseData));

    StructureBasicWall* pBasicBeam = opBasicWall.get();
    if (IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        pExternalDataComponent->RegisterExternalData(StructureBasicWall::GetStaticClassSchema()->GetName(), TransferOwnership(opBasicWall));
    }

    return pBasicBeam;
}

NdbObject* StructureBasicWall::GetTopOwnerObject() const
{
    const StructureWall* pBaseData = GetBaseData__().get();
    if (!pBaseData)
        return nullptr;
    return pBaseData->GetTopOwnerObject();
}